/*
 * Copyright (C) 2008 Yohan Liyanage. 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.nebulaframework.core.job.unbounded;

import java.io.Serializable;

import org.nebulaframework.core.job.GridJob;
import org.nebulaframework.core.job.ResultCallback;
import org.nebulaframework.core.job.annotations.unbounded.UnboundedProcessingSettings;
import org.nebulaframework.core.job.exceptions.InvalidResultException;
import org.nebulaframework.core.job.future.GridJobFuture;
import org.nebulaframework.core.job.splitaggregate.SplitAggregateGridJob;
import org.nebulaframework.core.task.GridTask;
import org.nebulaframework.grid.cluster.manager.ClusterManager;

/**
 * {@code UnboundedGridJob} provides the programming model for {@code GridJob}s
 * which are unbounded (the number of tasks are not bounded).
 * <p>
 * Unlike its counterpart {@link SplitAggregateGridJob},
 * {@code UnboundedGridJob} does not generate all tasks at once. Instead, the
 * {@link #task()} method will be invoked by the framework repetitively, and
 * each invocation should return the next {@code GridTask} to be executed on the
 * Nebula Grid. This allows an {@code UnboundedGridJob} to be <i>unbounded</i>,
 * thus allowing infinite number of tasks to be executed on the Nebula Grid.
 * <p>
 * If it is necessary, is possible to stop further task generation (task()
 * calls) by returning {@code null} from the task() method. If a {@code null}
 * value is returned from task() method, the default behavior is to stop the
 * {@code UnboundedGridJob} execution. But if it is necessary, the users are
 * allowed to disable this (that is, to ignore {@code null} values and continue)
 * through the {@link UnboundedProcessingSettings} annotation.
 * <p>
 * The {@link #processResult(Serializable)} method is invoked for each result
 * returned by the {@code GridTask}s generated by the {@link #task()} method.
 * This can be used to transform the result to another result, or to update
 * shared variables, or to be used as an input for future task generation.
 * However, note that this method is executed on the {@link ClusterManager} (not
 * distributed on Grid Nodes). Providing highly CPU-intensive code in
 * {@link #processResult(Serializable)} may slow down the overall job execution.
 * If a result is invalid (not acceptable), it is possible to request a
 * re-execution of the task by throwing {@link InvalidResultException} from this
 * method.
 * <p>
 * Furthermore, be advised that {@link #task()} and
 * {@link #processResult(Serializable)} methods are <b>executed on different
 * threads</b>, and the order of execution is not guaranteed. If it is
 * necessary to communicate between the two operations, the users are urged to
 * consider inter-thread communication mechanisms such as {@code wait()} and
 * {@code notify()}. Furthermore, if shared variables are used, ensure that
 * proper synchronization is maintained. <b>Failing to satisfy these
 * requirements may result in unexpected behavior</b>.
 * <p>
 * To obtain results of each task execution, a {@code ResultCallback} should be
 * utilized. This {@code ResultCallback} should be passed when the
 * {@code UnboundedGridJob} is submitted to the Grid. On each result, the
 * outcome of {@link #processResult(Serializable)} will be notified through the
 * {@code ResultCallback}. As the complete execution of all tasks are not
 * bounded, no result aggregation is supported by this programming model. Thus,
 * {@code UnboundedGridJob}s do not support final results and invoking 
 * {@link GridJobFuture#getResult()} or its overloaded versions will result in
 * an {@link IllegalStateException}.
 * <p>
 * Some customization of the execution of {@code UnboundedGridJob} is allowed
 * through {@link UnboundedProcessingSettings} annotation.If a {@code UnboundedGridJob}
 * is annotated with {@code ProcessingSettings}, the framework will detect
 * the settings and override the default settings with the provided ones.
 * Refer to {@link UnboundedProcessingSettings} for more information.
 * 
 * @param <T> Type of intermediate results of {@code GridTask}s
 * 
 * @author Yohan Liyanage
 * @version 1.0
 *  
 * @see UnboundedProcessingSettings
 * @see ResultCallback
 * @see SplitAggregateGridJob
 */
public interface UnboundedGridJob<T extends Serializable>
		extends GridJob<T, Serializable> {

	/**
	 * Invoked by the framework repetitively to obtain the 
	 * next {@code GridTask} to be executed on the Grid.
	 * 
	 * @return next {@code GridTask} to be executed
	 */
	public GridTask<T> task();

	/**
	 * Invoked when a result of execution of a {@code GridTask}
	 * is available. It is possible to transform the result
	 * to a different result with in this method. The return
	 * value of this method is considered as the final result
	 * of the task execution, and all {@link ResultCallback}s 
	 * will be informed with the return value. 
	 * 
	 * @param result result from task execution
	 * @return finalized result
	 * @throws InvalidResultException if result is not acceptable
	 */
	public Serializable processResult(Serializable result)
			throws InvalidResultException;

}
